﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Copad.BusinessCard.Model;
using System.Web.Script.Serialization;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Net;
using System.Threading.Tasks;
using System.Threading;
using Copad.BusinessCard.BLL;
using Intorise.Net;
using System.IO;
using System.Configuration;
using System.Text;

/// <summary>
///SyncHelper 的摘要说明
/// </summary>
public class SyncHelper
{
    static object syncLocker = new object();
    static object downloadImgLocker = new object();
    static JavaScriptSerializer serializer = new JavaScriptSerializer();
    static Dictionary<string, Action<Card, string>> dict = new Dictionary<string, Action<Card, string>>();
    static Regex startRegex = new Regex("({\"key\":\")([^\"]*)(\")", RegexOptions.IgnoreCase);
    static Regex endRegex = new Regex("({)([^}]*)(\"key\":\")([^\"]*)(\")", RegexOptions.IgnoreCase);
    static Regex jsonRegex = new Regex("{[^{}]*}");
    static Intorise.Net.NetTools tools = new Intorise.Net.NetTools();
    static bool isSyncRunning = false;
    static bool isDownloadImgRunning = false;
    static bool isCancelSync = false;
    static bool isCancelDownload = false;
    static int syncTotalCount = 0;
    static int syncCurrentIndex = 0;
    static int downloadImgTotalCount = 0;
    static int downloadImgCurrentIndex = 0;
    static int downloadedCount = 0;
    static StringBuilder downloadImageMessage = new StringBuilder();
    static StringBuilder syncMessage = new StringBuilder();

    static SyncHelper()
    {

        dict.Add("contact_id", (card, data) =>
        {
            decimal createDate = 0;
            var syncCardData = serializer.Deserialize<SyncCardData>(data);
            card.Summary.CardID = syncCardData.Contact_id;
            card.Summary.SyncID = syncCardData.Sync_cid;

            if (decimal.TryParse(syncCardData.Timecreate, out createDate))
            {
                card.Summary.CreateTime = createDate;
            }

            if (!string.IsNullOrEmpty(syncCardData.Group_id))
            {
                string[] categoryID = syncCardData.Group_id.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var x in categoryID)
                {
                    card.Category.Add(new CardCategory { CardID = card.Summary.CardID, CategoryID = x });
                }
            }
        });
        dict.Add("name", (card, data) =>
        {
            var syncCardName = serializer.Deserialize<SyncCardName>(data);
            card.Summary.Name = syncCardName.Username;
        });
        dict.Add("phone", (card, data) =>
        {
            var syncCardPhone = serializer.Deserialize<SyncCardPhone>(data);
            card.Number.Add(new CardPhoneNumber { CardID = card.Summary.CardID, Type = syncCardPhone.Type, Number = syncCardPhone.Value });
        });
        dict.Add("address", (card, data) =>
        {
            var syncCardAddress = serializer.Deserialize<SyncCardAddress>(data);
            card.Address.Add(new CardAddress { CardID = card.Summary.CardID, Address1 = syncCardAddress.Street1, Address2 = syncCardAddress.Street2, Zip = syncCardAddress.Zip, City = syncCardAddress.City });
        });
        dict.Add("front_pic", (card, data) =>
        {
            var syncCardFrontPic = serializer.Deserialize<SyncCardFrontPic>(data);
            card.Summary.FrontPic = syncCardFrontPic.Value;
        });
        dict.Add("back_pic", (card, data) =>
        {
            var syncCardBackPic = serializer.Deserialize<SyncCardBackPic>(data);
            card.Summary.BackPic = syncCardBackPic.Value;
        });
        dict.Add("company", (card, data) =>
        {
            var syncCardCompany = serializer.Deserialize<SyncCardCompany>(data);
            card.Company.Add(new CardCompany { CardID = card.Summary.CardID, Company = syncCardCompany.Company, Department = syncCardCompany.Department });
        });
        dict.Add("website", (card, data) =>
        {
            var syncCardWebsite = serializer.Deserialize<SyncCardWebsite>(data);
            card.Website.Add(new CardWebsite { CardID = card.Summary.CardID, Type = syncCardWebsite.Type, Url = syncCardWebsite.Value });
        });
        dict.Add("im", (card, data) =>
        {
            var syncCardIM = serializer.Deserialize<SyncCardIM>(data);
            int index = (syncCardIM.Type.IndexOf(';'));
            if (index > -1)
            {
                syncCardIM.Type = syncCardIM.Type.Substring(0, syncCardIM.Type.Length - index);
            }
            card.IM.Add(new CardIM { CardID = card.Summary.CardID, Type = syncCardIM.Type, Account = syncCardIM.Value });
        });
        dict.Add("note", (card, data) =>
        {
            var syncCardNote = serializer.Deserialize<SyncCardNote>(data);
            card.Remark.Add(new CardRemark { CardID = card.Summary.CardID, Type = RemarkTypeEnum.Text, Remark = syncCardNote.Value, RemarkDate = DateTime.Now, UserID = Manager.CurrentUser.User.ID, Username = Manager.CurrentUser.User.Username });
        });
        dict.Add("email", (card, data) =>
        {
            var syncCardEmail = serializer.Deserialize<SyncCardEmail>(data);
            card.Email.Add(new CardEmail { CardID = card.Summary.CardID, Type = syncCardEmail.Type, Email = syncCardEmail.Value });
        });
        dict.Add("nickname", (card, data) =>
        {
            var syncCardNickname = serializer.Deserialize<SyncCardNickname>(data);
            card.Summary.Nickname = syncCardNickname.Value;
        });
        dict.Add("template_id", (card, data) =>
        {

        });
        dict.Add("vacard_datas", (card, data) =>
        {

        });
        dict.Add("sns", (card, data) =>
        {
            var syncSns = serializer.Deserialize<SyncSns>(data);
            card.Number.Add(new CardPhoneNumber { CardID = card.Summary.CardID, Type = syncSns.Type, Number = syncSns.Value });
        });
    }

    public static int SyncTotalCount
    {
        get { return SyncHelper.syncTotalCount; }
    }

    public static int SyncCurrentIndex
    {
        get { return SyncHelper.syncCurrentIndex; }
    }

    public static int DownloadImgTotalCount
    {
        get { return SyncHelper.downloadImgTotalCount; }
    }

    public static int DownloadImgCurrentIndex
    {
        get { return SyncHelper.downloadImgCurrentIndex; }
    }

    public static string SyncMessage { get { return syncMessage.ToString(); } }
    public static string DownloadMessage { get { return downloadImageMessage.ToString(); } }

    public static bool IsSyncRunning { get { return isSyncRunning; } }
    public static bool IsDownloadImgRunning { get { return isDownloadImgRunning; } }

    public static Card GetCardData(CookieContainer container, string cardID)
    {
        Card card = null;
        try
        {
            var request = tools.SendRequest("https://www.camcard.com/card/contact");
            request.CookieContainer = container;
            string data = "action=c_info&json={\"contact_id\":\"" + cardID + "\"}";
            tools.PostData(data, request);
            var html = tools.GetResponseHtmlGzip((HttpWebResponse)request.GetResponse());
            html = html.Remove(0, 1);
            html = html.Remove(html.Length - 1, 1);

            card = new Card();
            card.Summary = new CardInfo();
            card.Summary.CardID = cardID;
            var matchess = jsonRegex.Matches(html);
            for (int i = 0; i < matchess.Count; i++)
            {
                var match = startRegex.Match(matchess[i].Value);
                if (match.Success)
                {
                    if (dict.ContainsKey(match.Groups[2].Value))
                    {
                        dict[match.Groups[2].Value](card, matchess[i].Value);
                    }
                    else
                    {

                    }
                }
                else
                {
                    var match0 = endRegex.Match(matchess[i].Value);
                    if (match0.Success)
                    {
                        if (dict.ContainsKey(match0.Groups[4].Value))
                        {
                            dict[match0.Groups[4].Value](card, matchess[i].Value);
                        }
                        else
                        {

                        }
                    }
                }
            }
        }
        catch
        {

        }
        return card;
    }

    public static SyncGroupInfo GetGroupInfo(CookieContainer container, SyncGroup group)
    {
        var request = tools.SendRequest("https://www.camcard.com/card/cardlist");
        request.CookieContainer = container;
        string data = "contact=ids&json={\"group_id\":\"" + group.ID + "\",\"langid\":\"zh-cn\",\"search\":\"\",\"start\":0,\"limit\":" + group.Sum + ",\"sum\":" + group.Sum + "}";
        tools.PostData(data, request);
        var html = tools.GetResponseHtmlGzip((HttpWebResponse)request.GetResponse());
        var ungroupedData = serializer.Deserialize<SyncGroupInfo>(html);
        return ungroupedData;
    }

    public static SyncGroupData GetGroupData(CookieContainer container)
    {
        var request = tools.SendRequest("https://www.camcard.com/tag/getall");
        request.CookieContainer = container;
        var html = tools.GetResponseHtmlGzip((HttpWebResponse)request.GetResponse());

        Regex regex = new Regex("var group_json = {.*};");
        var match = regex.Match(html);
        if (!match.Success)
        {
            throw new Exception("没有找到分组数据！");
        }

        string jsonText = match.Value.Replace("var group_json = ", "").Replace(";", "");
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        var groupData = serializer.Deserialize<SyncGroupData>(jsonText);
        return groupData;
    }

    public static CookieContainer Login()
    {
        Intorise.Net.NetTools tools = new Intorise.Net.NetTools();
        CookieContainer container = new CookieContainer();
        var request = tools.SendRequest("https://www.camcard.com/user/login");
        request.CookieContainer = container;
        string data = "act=submit&redirect=&username=13798049423&password=137980";
        tools.PostData(data, request);
        string html = tools.GetResponseHtmlGzip((HttpWebResponse)request.GetResponse());
        return container;
    }

    public static OperationResult Sync()
    {
        lock (syncLocker)
        {
            if (isSyncRunning)
            {
                return new OperationResult { Successful = false, Message = "一个同步任务正在运行，请稍后再试！" };
            }
            isSyncRunning = true;
            isCancelSync = false;
            syncCurrentIndex = 0;
            syncTotalCount = 0;
        }
        Task.Factory.StartNew(SyncMethod);
        return new OperationResult { Successful = true };
    }

    public static OperationResult DownloadImg()
    {
        lock (downloadImgLocker)
        {
            if (isDownloadImgRunning)
            {
                return new OperationResult { Successful = false, Message = "运行中" };
            }
            isDownloadImgRunning = true;
            downloadImgCurrentIndex = 0;
            isCancelDownload = false;
            downloadedCount = 0;
            downloadImageMessage.Clear();
        }
        if (!Directory.Exists(Manager.ImageRootPath))
        {
            downloadImgCurrentIndex = downloadImgTotalCount;
            isDownloadImgRunning = false;
            return new OperationResult { Successful = false, Message = "本地图片目录不存在！" };
        }
        Task.Factory.StartNew(DownloadImgMethod);
        return new OperationResult { Successful = true };
    }

    public static void SavePic(string picName, CookieContainer container)
    {
        FileStream fileStream = null;
        try
        {
            if (string.IsNullOrEmpty(picName))
            {
                return;
            }
            string filePath = Manager.ImageRootPath + picName;
            if (File.Exists(filePath)) { return; }
            var request = tools.SendRequest("https://cc1.camcard.com/sync/u/CamCard_Image/" + picName);
            request.CookieContainer = container;
            request.Timeout = 5000;
            request.KeepAlive = false;
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (Exception ex)
            {
                return;
            }
            if (response.StatusCode != HttpStatusCode.OK)
            {
                return;
            }
            var stream = response.GetResponseStream();
            fileStream = new FileStream(filePath, FileMode.OpenOrCreate);
            byte[] imgData = new byte[1024000];
            do
            {
                int length = stream.Read(imgData, 0, imgData.Length);
                if (length <= 0)
                {
                    break;
                }
                fileStream.Write(imgData, 0, length);
            } while (true);
            stream.Close();
            fileStream.Close();
            downloadedCount++;
        }
        catch (Exception ex)
        {
            Manager.WriteLog(ex);
            downloadImageMessage.AppendLine("下载" + picName + "出错：" + ex.Message);
        }
        finally
        {
            if (fileStream != null)
            {
                fileStream.Close();
            }
        }
    }

    private static void SyncMethod()
    {
        CookieContainer container = Login();
        var groupData = GetGroupData(container);
        List<Category> categories = new List<Category>();
        groupData.Custom_group.ForEach(x =>
        {
            categories.Add(new Category { CategoryID = x.ID, Name = x.Name });
        });
        CategoryBLL categoryBLL = new CategoryBLL();
        AutoResetEvent resetEvent = new AutoResetEvent(false);
        Task.Factory.StartNew(() => { categoryBLL.Sync(categories); resetEvent.Set(); });

        List<Card> list = new List<Card>();
        List<List<string>> idList = new List<List<string>>();
        List<bool> flags = new List<bool>();

        int copyIndex = 0;
        int sum = 100;

        var groupInfo = GetGroupInfo(container, groupData.Allcards);
        syncTotalCount = groupInfo.Data.Card_List.Count;
        while (groupInfo.Data.Card_List.Count > 0)
        {
            if (copyIndex + sum >= groupInfo.Data.Card_List.Count)
            {
                sum = groupInfo.Data.Card_List.Count - copyIndex;
            }
            else
            {
                sum = 100;
            }
            idList.Add(groupInfo.Data.Card_List.GetRange(copyIndex, sum));
            flags.Add(false);
            copyIndex += sum;
            if (copyIndex >= groupInfo.Data.Card_List.Count)
            {
                break;
            }
        }
        Trace.Listeners.Add(new ConsoleTraceListener());
        int count = 0;

        for (int i = 0; i < idList.Count; i++)
        {
            Task task = new Task(new Action<object>(index =>
            {
                List<string> ids = idList[(int)index];
                try
                {
                    ids.ForEach(id =>
                    {
                        var card = GetCardData(container, id);
                        if (card != null)
                        {
                            list.Add(card);
                            if (card.Category.Count == 0)
                            {
                                groupData.Custom_group.ForEach(g =>
                                {
                                    groupInfo = GetGroupInfo(container, g);
                                    if (groupInfo.Data.Card_List != null && groupInfo.Data.Card_List.Contains(card.Summary.CardID))
                                    {
                                        card.Category.Add(new CardCategory { CardID = card.Summary.CardID, CategoryID = g.ID });
                                    }
                                });
                            }
                        }
                        syncCurrentIndex++;
                        count++;
                        Trace.WriteLine(groupInfo.Data.Card_List.Count + "\\" + count);
                    });
                }
                finally
                {
                    flags[(int)index] = true;
                }
            }), i);
            task.Start();
        }

        while (true)
        {
            bool completed = true;
            flags.ForEach(x =>
            {
                completed = completed & x;
            });
            if (completed)
            {
                break;
            }
            if (isCancelSync)
            {
                isSyncRunning = false;
                isCancelSync = false;
                return;
            }
            Thread.Sleep(100);
        }

        CardBLL bll = new CardBLL();
        //AutoResetEvent resetEvent0 = new AutoResetEvent(false);
        //Task.Factory.StartNew(() =>
        //{
        //    list.ForEach(x =>
        //    {
        //        try
        //        {
        //            SavePic(x.Summary.FrontPic, container);
        //            SavePic(x.Summary.BackPic, container);
        //        }
        //        catch (Exception ex)
        //        {
        //            //记录到同步出错信息里，暂时没做。
        //        }
        //    });
        //    resetEvent0.Set();
        //});
        try
        {
            var result = bll.Sync(list);
            if (!result.Successful)
            {
                syncMessage.AppendLine("同步时出现错误，有" + result.RelateObject + "个名片未能同步！错误信息：" + result.Message);
            }
        }
        catch (Exception ex)
        {
            Manager.WriteLog(ex);
            syncMessage.AppendLine("保存到数据库时出现错误：" + ex.Message);
        }

        resetEvent.WaitOne();
        //resetEvent0.WaitOne();
        isSyncRunning = false;
    }

    private static void DownloadImgMethod()
    {
        CardBLL bll = new CardBLL();
        var list = bll.Get();
        downloadImgTotalCount = list.Count * 2;
        var container = SyncHelper.Login();
        foreach (var x in list)
        {
            if (isCancelDownload)
            {
                break;
            }
            SyncHelper.SavePic(x.FrontPic, container);
            SyncHelper.SavePic(x.BackPic, container);
            downloadImgCurrentIndex += 2;
        }
        isDownloadImgRunning = false;
        downloadImageMessage.AppendLine("图片下载完成，新下载了：" + downloadedCount + "张图片!");
    }
}
